<template>
	<el-card class="translate">
		<el-steps :space="200" :active="step" simple>
			<el-step title="选择项目" :icon="FolderOpened" />
			<el-step title="选择文件" :icon="FolderOpened" />
			<el-step title="选择语言" :icon="FolderOpened" />
			<el-step title="预览" :icon="FolderOpened" />
			<el-step title="导出" :icon="FolderOpened" />
		</el-steps>
		<template v-if="step === 1">
			<div class="translate-drop" @click="openFolder">
				<el-icon>
					<UploadFilled />
				</el-icon>
				<p>请选择项目</p>
			</div>
		</template>
		<template v-if="step === 2">
			<div class="translate-tree">
				<el-scrollbar>
					<el-tree :data="folder" :props="folderProps" show-checkbox ref="treeRef" />
				</el-scrollbar>
			</div>
			<div class="translate-buttons">
				<el-button type="primary" @click="onConfirmTree">确定</el-button>
				<el-button @click="onCancelTree">返回</el-button>
			</div>
		</template>
		<template v-if="step === 3">
			<div class="translate-preview">
				<el-scrollbar>
					<el-form :model="form" :rules="rules" label-position="left" ref="formRef">
						<el-form-item prop="from" label="当前语言">
							<el-select v-model="form.from" placeholder="请选择当前语言">
								<el-option v-bind="bindAttribute(key, 0)" v-for="(item, key) in StandardLocale" :label="item" />
							</el-select>
						</el-form-item>
						<el-form-item prop="to" label="目标语言">
							<el-select v-model="form.to" multiple placeholder="请选择目标语言">
								<el-option v-bind="bindAttribute(key, 1)" v-for="(item, key) in StandardLocale" :label="item" />
							</el-select>
						</el-form-item>
						<el-form-item prop="matcher" label="匹配方式">
							<el-select v-model="form.matcher" placeholder="请选择匹配方式">
								<el-option v-for="item in matchers" :label="item.name" :value="item.id"></el-option>
							</el-select>
						</el-form-item>
						<el-form-item prop="exporter" label="输出类型">
							<el-select v-model="form.exporter" placeholder="请选择输出类型">
								<el-option v-for="item in exporters" :label="item.name" :value="item.id" />
							</el-select>
						</el-form-item>
						<el-form-item  prop="translate" label="翻译平台">
							<el-select v-model="form.translate" placeholder="请选择翻译平台">
								<el-option v-for="item in translaters" :key="item.id" :value="item.id" :label="item.name" />
							</el-select>
						</el-form-item>
					</el-form>
				</el-scrollbar>
			</div>
			<div class="translate-buttons">
				<el-button type="primary" @click="onConfirmLanguage">确定</el-button>
				<el-button @click="onCancelLanguage">返回</el-button>
			</div>
		</template>
		<template v-if="step === 4">
			<div class="translate-preview">
				<el-scrollbar>
					<div class="preview-item" v-for="item in preview" :key="item.path">
						<div class="preview-item__remark">// {{ item.path }}</div>
						<div class="preview-item__data">
							<div class="preview-item__line" v-for="line in item.data">"{{ line }}" : "{{ line }}"</div>
						</div>
					</div>
				</el-scrollbar>
			</div>
			<div class="translate-buttons">
				<el-button type="primary" @click="onConfirmPreview">确定</el-button>
				<el-button @click="onCancelPreview">返回</el-button>
			</div>
		</template>
		
		<template v-if="step === 5">
			<div class="translate-progress">
				<el-progress :stroke-width="10" striped striped-flow :percentage="percentage"></el-progress>
				<div class="translate-progress__tips"> 共计{{ exported.progress.total }}项, 已完成{{ exported.progress.done }}项</div>
			</div>
			<div class="translate-preview">
				<el-scrollbar>
					<div class="log-item" v-for="item in exported.log" :key="item.id">
						<div class="log-item__date">{{ item.date }}</div>
						<div :class="['log-item__event', item.type]">
							<template v-if="item.type !== 'link'">[{{ item.tip }}]</template>
							<template v-else><a download="i18n.zip" :href="item.tip">点击导出</a></template>
						</div>
						<div class="log-item__message">{{ item.message }}</div>
					</div>
				</el-scrollbar>
			</div>
		</template>
	</el-card>
</template>

<script lang="ts" setup>
import { ref, type ComputedRef } from "vue";
import type { ElTree, FormRules, FormInstance } from 'element-plus'
import { ElNotification } from 'element-plus'
import { FolderOpened, UploadFilled } from '@element-plus/icons-vue'
import { openDirectory, deepClone, firstUppercase, sleep, getStoreConfig } from '@renderer/utils'
import { StandardLocale, translaters, matchers, exporters } from "@renderer/service"
import JsZip from "jszip";

const config = ref<ApplicationStoreConfig>()
onBeforeMount(async () => {
	config.value = await getStoreConfig()
})

const step = ref<number>(1)
function nextStep(){
	step.value ++
}

//#region 目录选择

const folder = ref<Array<IDirectory>>([])
const folderProps = { label: 'name', children: 'children'}
// 打开目录
async function openFolder(){
	const result = await openDirectory()
	if (result.canceled) return
	const path = result.filePaths[0]
	folder.value = await window.bridge.readDirectory(path, undefined, deepClone(config.value?.common.exclude ?? []))
	nextStep()
}

// #endregion


//#region 文件选择

const treeRef = ref<InstanceType<typeof ElTree>>()

const treeSelected = ref<Array<IDirectory>>([])

// 点击确定
const onConfirmTree = () => {
	const nodes = treeRef.value!.getCheckedNodes(true,true) as Array<IDirectory>
	const files = nodes.filter(item => item.type === 'file')
	if(files.length < 1){
		ElNotification.error({ title: '操作失败', message: '请选择文件' })
		return
	}
	treeSelected.value =  files
	nextStep()
}

// 点击取消
const onCancelTree = () => {
	treeSelected.value = []
	step.value --
}

//#endregion


//#region 文件预览


const preview = ref<Array<PacketData>>([])

const getPreviewData = async () => {
	const cached = new Set<string>()
	for(let item of treeSelected.value){
		const content = await window.bridge.readFile(item.path)
		const matcher = Object.values(matchers).find(matcher => matcher.id === form.matcher)!
		const matched = matcher.match(content)
		const filterMatched = matched.filter(item => {
			if(cached.has(item)) return false
			cached.add(item)
			return true
		})
		const packet = packetData(filterMatched, item.relative)
		if(Object.keys(packet.data).length > 0) preview.value.push(packet)
	}
}

// 数据结构包装
const packetData = (matched: Array<string>, path: string) : PacketData => {
	const data:Record<string, string> = {}
	for(let key of matched){ data[key] = key }
	return { path, data }
}

// 点击确定
function onConfirmPreview(){
	nextStep()
	startTranslateTask()
}

// 点击取消
function onCancelPreview(){
	step.value --
	preview.value = []
}

//#endregion


//#region 语言选择

interface FormTypes{
	from: string,
	to: Array<string>,
	matcher: string,
	exporter: string,
	translate: string | number
}

const form = reactive<FormTypes>({
	from: '',
	to: [],
	matcher: '',
	exporter: '',
	translate: ''
})


// 表单校验规则
const rules = reactive<FormRules>({
	from: [{required: true, message: '请选择当前语言', trigger: 'change'}],
	to: [{required: true, type: 'array', message: '请选择目标语言', trigger: 'change'}],
	exporter: [{required: true, message: '请选择输出类型', trigger: 'change'}],
	matcher: [{required: true, message: '请选择匹配方式', trigger: 'change'}],
	translate: [{required: true, message: '请选择翻译', trigger: 'change'}],
})

const bindAttribute = computed(() => {
	return (value, type) => {
		const attribute = { value }
		if(type === 0 && form.to.includes(value)) attribute['disabled'] = true
		if(type === 1 && form.from === value) attribute['disabled'] = true
		return attribute
	}
})

// 点击确定
const formRef = ref<FormInstance>()
const onConfirmLanguage = () => {
	formRef.value?.validate(valid => {
		if(!valid) return
		nextStep()
		getPreviewData()
	})
}

// 点击返回
const onCancelLanguage = () => {
	step.value --
	form.from = form.translate = form.matcher = ''
	form.to = []
}
//#endregion

//#region 导出

interface LogInfo {
	id: string,
	type: string,
	message: string,
	tip: string,
	date: string
}

interface ExportedTypes {
	log: Array<LogInfo>,
	data: Array<TranslateTaskResult>,
	progress: {
		done: number,
		total: ComputedRef<number>
	}
}

const exported = reactive<ExportedTypes>({
	log: [],
	data: [],
	progress: {
		done: 0,
		total: computed(() => preview.value.reduce((prev, item) => {
			return prev + Object.keys(item.data).length * form.to.length
		},0))
	}
})

const percentage = computed<number>(() => {
	const { done, total } = exported.progress
	if(total === 0) return 0
	return Math.floor((done / total) * 100)
})

// @ts-ignore
const startTranslateTask = async () => {
	
	const translator = Object.values(translaters).find(item => item.id === form.translate)!

	// 保存一份源数据
	let fromData: TranslateTaskResult = { locale: form.from, data: deepClone(preview.value) }
	exported.data.push(fromData)
	// 翻译目标语言
	for(let locale of form.to){
		const data: TranslateTaskResult = { locale, data: [] }
		for(let packet of preview.value){
			let packetData: PacketData = { path: packet.path, data: {} }
			for(let keyword in packet.data){
				try{
					logger.info(`${keyword} (${StandardLocale[form.from]} -> ${StandardLocale[locale]})`,'正在翻译')
					const result = await translator.translate(keyword, locale, form.from)
					result.data = firstUppercase(result.data)
					packetData.data[keyword] = result.data
					logger.success( `${keyword} -> ${ result.data }` ,'翻译成功')
				}catch(e){
					packetData.data[keyword] = ''
					logger.error(`${keyword}`, '翻译失败')
				}
				exported.progress.done++
				await sleep(translator.delay)
			}
			data.data.push(packetData)
		}
		exported.data.push(data)
	}
	logger.success('全部翻译完成','翻译完成')

	createZipBundle()
}

// 压缩包生成
function createZipBundle(){
	const jsZip = new JsZip()
	const exporter = Object.values(exporters).find(exporter => exporter.id === form.exporter)!
	const data = exporter.export(exported.data)
	for(let fileName in data){
		jsZip.file(fileName, data[fileName])
	}
	jsZip.generateAsync({type: 'blob'}).then(blob => {
		const objectURL = URL.createObjectURL(blob)
		logger.link('生成成功', objectURL)
		const a = document.createElement('a')
		a.download = 'i18n.zip'
		a.href = objectURL
		a.click()
	})
}


const logger = {
	success(message: string, tip: string){
		this.print(message,tip, 'success')
	},
	error(message: string, tip: string){
		this.print(message,tip, 'error')
	},
	info(message: string, tip: string){
		this.print(message,tip, 'info')
	},
	link(message: string, tip: string){
		this.print(message,tip, 'link')
	},
	print(message: string, tip:string, type: string){
		exported.log.unshift({ message , tip, type, date: new Date().toLocaleString(), id: crypto.randomUUID() })
	}
}

</script>


<style lang="scss" scoped>
@use './translate.scss'
</style>
